'Trying to put working arcpy.SearchCursor code into a function

I have python code that uses arcpy.SearchCursor to look for unique values in a field (Native_Species, in my case), and put them into a list. Then I use list comprehension to remove None values, sort the list, and print. This code works.

# Create empty list, use .SearchCursor to populate list with unique values
myList = []
rows = arcpy.SearchCursor(monitoring)
for row in rows:
    if row.Native_Species not in myList:
        myList.append(row.Native_Species)

# Use list comprehension to remove None values in list
res = [i for i in myList if i]

# Sort list and print
res.sort()
print(*res, sep = '\n')

I would like to put this code into a function, where I can list only unique values across multiple fields in a given feature class. This is what I have tried:

def listUnique(fc, fields):
    myList = []
    with arcpy.da.SearchCursor(fc, fields) as cursor:
        for row in cursor:
            if row.fields not in myList:
                myList.append(row.fields)
        res = [i for i in myList if i]
        res.sort()
        print(*res, sep = '\n')

This gives me an error "'tuple' object has no attribute 'fields'".

How should I put my working code into a function, where I can specify a given input feature class, and a list of fields within that feature class, and get back a list of only unique values across those fields?

Thank you!



Solution 1:[1]

The output is not real pretty. Might be more useful to create a unique value list for every feature class column. Hopefully this will give you some ideas to get what you need.

import arcpy

# set the workspace to the geodatabase the feature class is in
arcpy.env.workspace = r'\path\to\your\geodatabase.gdb'

def uniqueValues(fc):
    # create a list of unique values from all rows and columns in a feature class
    #create an empty list to store all values in the feature class
    tableList = []
    #Get all values in the feature class and append them to tableList
    fcList = arcpy.ListFeatureClasses(fc)
    for fc in fcList:
        with arcpy.da.SearchCursor(fc, "*") as cursor:
            for row in cursor:
                for value in row:
                    tableList.append(value)
    print('The list length of all values is ' + str(len(tableList)))
    # Create an empty list to store the unique values in the feature class
    uniqueList = []
    # use set to drop duplicates
    uniqueSet = set(tableList)
    print('The list length of unique values is ' + str(len(uniqueSet)))
    # put the items from the set back into a list.  add all values to the list as strings to avoid data type problems
    for item in uniqueSet:
        uniqueList.append(str(item))
    # remove none values from the list
    uniqueList = [i for i in uniqueList if i]
    # sort the list
    uniqueList = sorted(uniqueList)
    print(*uniqueList, sep = '\n')

# call the function and enter the name of the feature class as the parameter
uniqueValues('Enter Feature Class Name')

Solution 2:[2]

This is a rather confusing point for beginners in Python: are we in a package?

The general rule is that Python can only import modules from the current directory for from a directory contained in sys.path. But as having multiple related modules to build a large thing is common (small is beautiful is a general rule in programming...), Python has a notion of package. A (non namespace) package is a subtree with 2 conditions:

  • the top level folder is directly accessible (ie is a subdir of the current folder or of a folder from sys.path)
  • the top level folder contains a __init__ file.

When both conditions are met, the directory becomes a (non namespace) package and the modules it contains can be accessed (or imported) using dotted expressions.

And relative imports using dotted expressions are only valid in a module that was loaded as a member of a package. Being in a folder containing a __init__.py file is not enough.

If we have this folder:

top
|- __init__.py
|- a.py
|- b.py

if the current directory is the parent directory of top, and is a.py contains from . import b

Then you can successfully run python -m top.a because a.py is loaded as a member of the top package.

But python top/a.py will raise an import error.


Namespace package are a more advanced concept that allows a package to be scattered in different places. Refere to the official documentation for more...

Solution 3:[3]

Do you have any module that is named "."? Probably not. Refering to the module with "." only works, if you're inside the module "."

What you probably want to do is:

import sys
sys.path.append('/.../testimports/package1')

import b

b.run()

Here is a guide on python modules

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3