Python TipsAndTricks

From Valve Developer Community
Jump to navigation Jump to search
Wikipedia - Letter.png
This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these template messages)
Dead End - Icon.png
This article has no Wikipedia icon links to other VDC articles. Please help improve this article by adding links Wikipedia icon that are relevant to the context within the existing text.
January 2024

Some tips to help you out

Class Defines

If you add no_init to a class define then that class cant be constructed via python. This is good for classes like players, weapons and entitys that have a special method of constuction.
Example:

bp::class_< NoNew >("CantMakeMe", bp::no_init);

A lot of classes in Source are non copyable (i.e. you use pointers to reference them not stack objects) and thus you will need to state that they are non copyable otherwise strange compile errors or run time errors occur. This doesnt mean you cant make multiplie objects in python that point to this, just that boost wont try and copy it in the python bindings.

bp::class_< NoCopy, boost::noncopyable >("BoostCantCopyMe", bp::no_init);

Function Defines

When a function (or member function) your rapping returns a pointer you will have to tell boost how to handle it. If your return a new object, boost needs to know to hang onto and if you return a pointer to an existing object you have to boost to just use it. If you do the latter your python classes shouldnt hold on to the object as boost only ensures its valid for the lifetime of the function call.


Example New Object:

MyClass* pyGetNewClass()
{
   return new MyClass();
}

bp::def("NewClass", pyGetNewClass, bp::return_value_policy<bp::manage_new_object>()); //callee needs to delete it


Example Existing Object:

CBasePlayer* pyGetPlayerByIndex(int index)
{
   return UTIL_PlayerByIndex(index);
}

bp::def("GetPlayerByIndex", pyGetPlayerByIndex, bp::return_value_policy<bp::reference_existing_object>()); //callee doesnt need to delete it

Function Calls

If your passing a pointer to a python function call and you marked the class as non copyable (see above) you will need to wrap it in the function ptr().
Example:

virtual void OnPlayerKilled(CBasePlayer *pVictim, CBasePlayer *pKiller, CBaseEntity *pWeapon)
{
	this->get_override("OnPlayerKilled")(bp::ptr(pVictim), bp::ptr(pKiller), bp::ptr(pWeapon));
}