What is a "property" used for in Python? - python

I was editing a blog post and started to type the word property when my autocomplete suggested a completion called new Property, curious as ever I looked it up and found that this was coming from the Python autocomplete package.
I pressed it and this code appeared:
def foo():
doc = "The property."
def fget(self):
return self._
def fset(self, value):
self._ = value
def fdel(self):
del self._
return locals()
= property(**())
I typed Grape where the cursor(s) were, so I ended up with this:
def Grape():
doc = "The Grape property."
def fget(self):
return self._Grape
def fset(self, value):
self._Grape = value
def fdel(self):
del self._Grape
return locals()
Grape = property(**Grape())
By looking at the code I can see that it's creating a local variable called doc but doesn't seem to be doing anything with it.
It's also creating three functions, one which returns self._Grape another which adds a new property to self._Grape and one which deletes self._Grape.
Where did self & _Grape come from? Is this a class of some sort, like a "pseudo class"?
Where, why and how are "new Properties" used?

Your editor is providing an unusual way to create a property. Here is some information on properties.
After reading that, you'll realize that there's no need to create the getter and setter within a function. The reason the editor does it this way is to have a scope where to define the names of the getter and setter without needing unique names. IOW, the names are hidden in the function.
So, how are the objects defined in the function (fget, fset, fdel & doc) passed to the property descriptor?
Notice the function returns the result of locals. So the return value of the function is a dict with the name of the local objects as keys and the local objects as values.
Finally, regarding self, fget, fset and fdel will be executed as if they were methods of the object which has the property so self refers to that object.

Related

Python how to get self from class function?

Can I get self from class function? For example:
class abc:
def __init__(self, name):
self.name = name
def printname(self):
print(self.name)
x = abc("test").printname()
I want to get original class obj abc("test") from x without using return self or define x = abc("test") at first, is it possible?
The short answer is no.
The longer answer:
printname is not a "class function", it's an instance method. A class method is one that takes the class as the first parameter. Most methods are instance methods; they take self (a particular instance of the class) as the first parameter. If this were indeed a class method, there would be no "self" associated with it.
The thing you're referring to as a "class object" is an instance of the class abc. abc is itself an object (everything in Python is an object, including class definitions), but that's not the same thing as the instance you get by calling abc("test").
Any time you want to take a value that's local to a particular function call and make it available to the caller (including its parameters), you need to return it. There are technically other tricks involving mutating state in the caller's scope, but those aren't applicable to your example. If you ended printname with the line return self, then doing x = abc("test").printname() would result in the instance being assigned to x.
In your example, the caller is the one that constructs the instance, so simply writing this would also do the trick:
x = abc("test")
x.printname()

Python Function that creates class instances

Hello i want to create a function which creates instances of a class
def make_instance(name_instance)
name_instance=puppy()
class puppy:
def __init__(self,name):
self.name =name
make_instance(cloud)
# when i pass an argument it says the variable is undefined and i use #isinstance() it return False.
Your puppy class needs to take a name value into its constructor, and you're currently not passing in anything.
Also your function doesn't return the instance at all. It simply re-assigns the instance to the variable name_instance that you pass in (losing your input). The return value of make_instance right now is None
My guess is that you want your implementation to look like the following
def make_instance(name_instance)
return puppy(name_instance)
I do want to point out though that this function isn't useful unless it does more than just create the instance, you're just adding wrapper code around the constructor

Python naming convention for setter method name without args

I have been writing python code with classes that will have a method called something like:
def set_log_paths(self):
The thing is, this method doesn't take an argument, it determines what some values should be based on other values of self. Is it inappropriate to use the word "set" in this case? I ask because it isn't a direct getter or a setter as one would use in a language with private members.
Is there a common conventional word to use in my method name?
f you don't pass any values, and instead, compute the value at the moment the method is called, based on current values, it is reasonable that the verb describing the action be "update" - therefore update_log_paths().
Just double check you really need this design, and what are the chances of you/other users of your class forgetting calling these "update" methods.
Python's introspection easily allows adopting some elements from "reactive programing", which could be used to trigger these updater methods when the values they depend upon are changed.
One optimal choice for such an architecture would be a descriptor for your properties that upon having __set__ called would check a class-level registry to "see" if events should be triggered, and then one decorator that would enable you to list the attributes that would trigger it. A base class with a proper __init_subclass__ method could set everything up.
Let's suppose you will have the "base properties" on your class as annotated attributes in the class body - the descritptor, decorator and base-class code for this to work could be something along:
from functools import wraps
from collections import ChainMap
class EventDescriptor:
def __init__(self, name, default):
self.name = name
self.default = default
def __get__(self, instance, owner):
if not instance:
return self
return instance.__dict__[self.name] if self.name in instance.__dict__ else self.default
def __set__(self, instance, value):
instance.__dict__[self.name] = value
triggers = instance._post_change_registry.get(self.name, [])
for trigger in triggers:
getattr(instance, trigger)()
def triggered_by(*args):
def decorator(func):
func._triggered_by = args
return func
return decorator
class EventPropertyMixin:
def __init_subclass__(cls, **kw):
super.__init_subclass__(**kw)
for property_name, type_ in cls.__annotations__.items():
if not hasattr(cls, property_name):
raise TypeError("Properties without default values not supported in this example code")
# It would also be trivial to implement runtime type-checking in this point (and on the descriptor code)
setattr(cls, property_name, EventDescriptor(property_name, getattr(cls, property_name)))
# collects all registries in ancestor-classes, preserving order:
post_change_registry = ChainMap()
for ancestor in cls.__mro__[:0:-1]:
if hasattr(ancestor, "_post_change_registry"):
post_change_registry = post_change_registy.new_child(ancestor._post_change_registry)
post_change_registry = post_change_registry.new_child({})
for method_name, method in cls.__dict__.items():
if callable(method) and hasattr(method, "_triggered_by"):
for property_name in method._triggered_by:
triggers = post_change_registry.setdefault(property_name, [])
if method_name not in triggers:
triggers.append(method_name)
cls._post_change_registry = post_change_registry
class Test(EventPropertyMixin):
path1: str = ""
path2: str = ""
#triggered_by("path1", "path2")
def update_log_paths(self):
self.log_paths = self.path1 + self.path2
And let's this working:
In [2]: t = Test()
In [3]: t.path1 = "/tmp"
In [4]: t.path2 = "/inner"
In [5]: t.log_paths
Out[5]: '/tmp/inner'
So, this is complicated code, but code that usually would lie inside a framework, or in base utility libraries - with these 50 lines of code, you could be using Python to work for you, and have it call the updating methods, so their name won't matter at all! :-)
(ok, this code is way overkill for the question asked - but I was in a mood to produce something like this before sleeping tonight - disclaimer: I had not tested the inheritance-related corner cases covered in here)

Getter and Setter for member variable in Python

I know that it is not recommended to write getter and setter for class member variables in Python. Still I need to do it because I have a complex object which internally contains a lot of objects in depth. I need to expose a property/function in container object that will get and/or set member of inner object. How can I do this in Python?
def responseoperationcode(self,operationcode=None):
if operationcode:
self.innerobject.operationcode=operationcode
else:
return self.innerobject.operationcode
Above given function can act as a getter and setter but the syntax to use it would be confusing. My requirement is that user should get its value without using parenthesis and to set values he should pass parameters. Something like this
objectname.responseoperationcode ##this should return the value
and
objectname.responseoperationcode("SUCCESS")##this should set the value
Please suggest.
Python supports properties. You can change your code to:
#property
def responseoperationcode(self):
return self.innerobject.operationcode
#responseoperationcode.setter
def responseoperationcode(self, value):
self.innerobject.operationcode = value
Now you can use the responseoperationcode function like a field, e.g.:
objectname.responseoperationcode # this returns the value
objectname.responseoperationcode = "SUCCESS" # this sets the value
Well, if you have access to the definition of the inner objects, you could write a getter method there. Then whole thing would look similar to this:
class OuterObject:
innerObject
def getInnerField(self, field=None):
if field == None:
return self.innerObject.getField()
else:
self.innerObject.setField(field)
class InnerObject:
field
def getField(self):
return self.field
def setField(self, field):
self.field = field

Hide deprecated methods from tab completion

I would like to control which methods appear when a user uses tab-completion on a custom object in ipython - in particular, I want to hide functions that I have deprecated. I still want these methods to be callable, but I don't want users to see them and start using them if they are inspecting the object. Is this something that is possible?
Partial answer for you. I'll post the example code and then explain why its only a partial answer.
Code:
class hidden(object): # or whatever its parent class is
def __init__(self):
self.value = 4
def show(self):
return self.value
def change(self,n):
self.value = n
def __getattr__(self, attrname):
# put the dep'd method/attribute names here
deprecateds = ['dep_show','dep_change']
if attrname in deprecateds:
print("These aren't the methods you're looking for.")
def dep_change(n):
self.value = n
def dep_show():
return self.value
return eval(attrname)
else:
raise AttributeError, attrname
So now the caveat: they're not methods (note the lack of self as the first variable). If you need your users (or your code) to be able to call im_class, im_func, or im_self on any of your deprecated methods, then this hack won't work. Also, i'm pretty sure there's going to be a performance hit because you're defining each dep'd function inside __getattr__. This won't affect your other attribute lookups (had I put them in __getattribute__, that would be a different matter), but it will slow down access to those deprecated methods. This can be (largely, but not entirely) negated by putting each function definition inside its own if block, instead of doing a list-membership check, but, depending on how big your function is, that could be really annoying to maintain.
UPDATE:
1) If you want to make the deprecated functions methods (and you do), just use
import types
return types.MethodType(eval(attrname), self)
instead of
return eval(attrname)
in the above snippet, and add self as the first argument to the function defs. It turns them into instancemethods (so you can use im_class, im_func, and im_self to your heart's content).
2) If the __getattr__ hook didn't thrill you, there's another option (that I know of) (albiet, with its own caveats, and we'll get to those): Put the deprecated functions definitions inside __init__, and hide them with a custom __dir__. Here's what the above code would look like done this way:
class hidden(object):
def __init__(self):
self.value = 4
from types import MethodType
def dep_show(self):
return self.value
self.__setattr__('dep_show', MethodType(dep_show, self))
def dep_change(self, n):
self.value = n
self.__setattr__('dep_change', MethodType(dep_change, self))
def show(self):
return self.value
def change(self, n):
self.value = n
def __dir__(self):
heritage = dir(super(self.__class__, self)) # inherited attributes
hide = ['dep_show', 'dep_change']
show = [k for k in self.__class__.__dict__.keys() + self.__dict__.keys() if not k in heritage + private]
return sorted(heritage + show)
The advantage here is that you're not defining the functions anew every lookup, which nets you speed. The disadvantage here is that because you're not defining functions anew each lookup, they have to 'persist' (if you will). So, while the custom __dir__ method hides your deprecateds from dir(hiddenObj) and, therefore, IPython's tab-completion, they still exist in the instance's __dict__ attribute, where users can discover them.
Seems like there is a special magic method for the introcpection which is called by dir(): __dir__(). Isn't it what you are lookin for?
The DeprecationWarning isn't emitted until the method is called, so you'd have to have a separate attribute on the class that stores the names of deprecated methods, then check that before suggesting a completion.
Alternatively, you could walk the AST for the method looking for DeprecationWarning, but that will fail if either the class is defined in C, or if the method may emit a DeprecationWarning based on the type or value of the arguments.
About the completion mechanism in IPython, it is documented here:
http://ipython.scipy.org/doc/manual/html/api/generated/IPython.core.completer.html#ipcompleter
But a really interesting example for you is the traits completer, that does precisely what you want to do: it hides some methods (based on their names) from the autocompletion.
Here is the code:
http://projects.scipy.org/ipython/ipython/browser/ipython/trunk/IPython/Extensions/ipy_traits_completer.py

Categories

Resources